package demo.dcs.aspect;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.PooledDataSource;
import demo.dcs.MertricListener;
import demo.dcs.MertricSendSchedule;
import demo.dcs.util.XdcsBeanUtils;
import demo.dcs.vo.XdcsSparkConstant;
import demo.java.lang.management.jvm.AppTraceConfig;
import demo.java.lang.management.vo.MetricSpan;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


/**
 * @author mandy.hu
 *
 */
public class DataSourceAspectJ extends AbstractXdcsAspectJ implements MertricListener {

	private static final Logger logger = LoggerFactory.getLogger(DataSourceAspectJ.class);

    private static boolean isC3p0DataSource = XdcsBeanUtils.isClassExist("com.mchange.v2.c3p0.PooledDataSource");

    private PooledDataSource pds;

    private String dataSourceName;

    public DataSourceAspectJ(){
//    	MertricSendSchedule.getMertricSendSchedule().addMertricListener(this);
    }

    public String getDataSourceName() {
        return this.dataSourceName;
    }

    public PooledDataSource getPds() {
        return pds;
    }

    @Override
    public boolean isDestroyed(){
		boolean destroy = false;

		if(this.pds != null){
			try {
				pds.getNumConnectionsDefaultUser();
				pds.getNumBusyConnectionsDefaultUser();
				pds.getNumIdleConnectionsDefaultUser();
			} catch (SQLException e) {
				destroy = true;
			}
		}else{
			destroy = true;
		}

        return destroy;
//        boolean destroy = true;
//        if (this.pds!=null){
//            destroy = XdcsC3p0ComboPooledReflectUtil.isPoolClosed(this.pds);
//        }
//        return destroy;
    }
	@Override
	public boolean isSameSource(MertricListener listener) {
		if (listener==null || !(listener instanceof DataSourceAspectJ)) {
			return false;
		}
		DataSourceAspectJ dataSourceAspectJ = (DataSourceAspectJ) listener;
        if (StringUtils.equalsIgnoreCase(this.getDataSourceName(), dataSourceAspectJ.getDataSourceName())) {
			return true;
		}
		return false;
	}
	@Override
	public String getMertricListenerType() {
		
		return "c3p0-pool:"+this.getDataSourceName();
	}


    @Override
    public boolean isSame(MertricListener listener) {
        if (listener==null)
            return false;
        if (!(listener instanceof DataSourceAspectJ))
            return false;
        if (((DataSourceAspectJ) listener).pds!=this.pds)
            return false;
        return true;
    }

    @Override
	public List<MetricSpan> collectMetric() {
    	List<MetricSpan> metricSpans = new ArrayList<MetricSpan>();
        if (pds == null) return metricSpans;
        if (isDestroyed()) {
        	MertricSendSchedule.getMertricSendSchedule().deleteMertricListener(this);
        	return null;
		}

    	long timestamp = System.currentTimeMillis();
    	MetricSpan metricSpan = new MetricSpan();
    	metricSpan.setTimestamp(timestamp);
    	metricSpan.setMetric(XdcsSparkConstant.DB_DATASOURCE_METRIC);
    	metricSpan.getTags().put(XdcsSparkConstant.TAG_APP, AppTraceConfig.getLocalConfig().getAppName());
    	metricSpan.getTags().put(XdcsSparkConstant.TAG_IP, AppTraceConfig.getLocalConfig().getIp());
    	metricSpan.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_CONNECT,XdcsSparkConstant.TAG_NUM_CONNECT);
    	metricSpan.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_NAME,this.getDataSourceName());
    	try {
			metricSpan.setValue(pds.getNumConnectionsDefaultUser());
		} catch (SQLException e) {
			logger.error("DataSourceAspectJ getNumConnectionsDefaultUser error", e);
		}
    	metricSpans.add(metricSpan);
    	
    	MetricSpan metricSpan1 = new MetricSpan();
    	metricSpan1.setTimestamp(timestamp);
    	metricSpan1.setMetric(XdcsSparkConstant.DB_DATASOURCE_METRIC);
    	metricSpan1.getTags().put(XdcsSparkConstant.TAG_APP, AppTraceConfig.getLocalConfig().getAppName());
    	metricSpan1.getTags().put(XdcsSparkConstant.TAG_IP, AppTraceConfig.getLocalConfig().getIp());
    	metricSpan1.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_CONNECT,XdcsSparkConstant.TAG_NUM_BUSY_CONNECT);
    	metricSpan1.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_NAME,this.getDataSourceName());
    	try {
			metricSpan1.setValue(pds.getNumBusyConnectionsDefaultUser());
		} catch (SQLException e) {
			logger.error("DataSourceAspectJ getNumBusyConnectionsDefaultUser error",e);
		}
    	metricSpans.add(metricSpan1);
    	
    	
    	MetricSpan metricSpan2 = new MetricSpan();
    	metricSpan2.setMetric(XdcsSparkConstant.DB_DATASOURCE_METRIC);
    	metricSpan2.getTags().put(XdcsSparkConstant.TAG_APP, AppTraceConfig.getLocalConfig().getAppName());
    	metricSpan2.getTags().put(XdcsSparkConstant.TAG_IP, AppTraceConfig.getLocalConfig().getIp());
    	metricSpan2.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_CONNECT,XdcsSparkConstant.TAG_NUM_IDLE_CONNECT);
    	metricSpan2.setTimestamp(timestamp);
    	metricSpan2.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_NAME,this.getDataSourceName());
    	try {
			metricSpan2.setValue(pds.getNumIdleConnectionsDefaultUser());
		} catch (SQLException e) {
			logger.error("DataSourceAspectJ getNumIdleConnectionsDefaultUser error",e);
		}
    	metricSpans.add(metricSpan2);

        MetricSpan metricSpan3 = new MetricSpan();
        metricSpan3.setMetric(XdcsSparkConstant.DB_DATASOURCE_METRIC);
        metricSpan3.getTags().put(XdcsSparkConstant.TAG_APP, AppTraceConfig.getLocalConfig().getAppName());
        metricSpan3.getTags().put(XdcsSparkConstant.TAG_IP, AppTraceConfig.getLocalConfig().getIp());
        metricSpan3.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_CONNECT,XdcsSparkConstant.TAG_NUM_MAX_CONNECT);
        metricSpan3.setTimestamp(timestamp);
        metricSpan3.getTags().put(XdcsSparkConstant.TAG_DATA_SOURCE_NAME,this.getDataSourceName());
        metricSpan3.setValue(((ComboPooledDataSource) pds).getMaxPoolSize());
        metricSpans.add(metricSpan3);

		return metricSpans;
	}

    @Override
	public void beforeAspectJ(Object signature, Object instance, Object[] args) {

		
	}

	@Override
	public void afterAspectJ(Object result, Object signature, Object instance, Object[] args, Throwable throwable) {
		try {
			if (!mercurySwitch()) {
				return;
			}
            if (!isC3p0DataSource){
                return;
            }
			if (instance instanceof PooledDataSource) {   
				pds = (PooledDataSource) instance;
                if (instance!=null){
                    this.dataSourceName = StringUtils.split(((ComboPooledDataSource) pds).getJdbcUrl(), "?")[0];
                    MertricSendSchedule.getMertricSendSchedule().addMertricListener(this);
                }
			}
		} catch (Throwable e) {
			logger.error("DataSourceAspectJ afterAspectJ", e);
		}
	}

	
	/**
	 * @param dataSourceName the dataSourceName to set
	 */
	public void setDataSourceName(String dataSourceName) {
	
		this.dataSourceName = dataSourceName;
	}


}
